package com.naiterui.ehp.bs.emr.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Chunk;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.text.pdf.draw.LineSeparator;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;

import lombok.Builder;
import lombok.Data;

/**
 * @author guoyongxiang
 * @date 2019/9/10 20:05
 * @since 1.0.0
 */
@Component
public class EmrPdfUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(EmrPdfUtil.class);

    private static final String HOSPITAL_SEAL_PATH = ConfigUtil.getString("prescription.seal.path");
    private static final String PDF_FILE_BASE_PATH = ConfigUtil.getString("emr.file.pdf.path");
    @Value("${file.base.prefix}")
    private String basePath;

    BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
    BaseFont bfEnglish = BaseFont.createFont(BaseFont.HELVETICA, "", BaseFont.NOT_EMBEDDED);

    Font firsetTitleFont = new Font(bfChinese, 22, Font.BOLD); // 一级标题
    Font secondTitleFont = new Font(bfChinese, 15, Font.BOLD); // 二级标题
    Font secondTitleFontEn = new Font(bfEnglish, 15, Font.BOLD); // 二级标题-EN
    Font fontContent = new Font(bfChinese, 8, Font.NORMAL);
    Font fontContent2 = new Font(bfChinese, 9, Font.BOLD, BaseColor.DARK_GRAY);
    Font fontContentBOLD = new Font(bfChinese, 10, Font.BOLD);
    Font fontContentEn = new Font(bfEnglish, 10, Font.NORMAL);
    LineSeparator line = new LineSeparator(1f, 100, BaseColor.GRAY, Element.ALIGN_CENTER, -3f);
    LineSeparator line2 = new LineSeparator(1f, 95, new BaseColor(238, 238, 238), Element.ALIGN_CENTER, -2f);

    public EmrPdfUtil() throws IOException, DocumentException {
    }

    public String generatePDF(EmrBO emr) throws IOException, DocumentException {
        long start = System.currentTimeMillis();
        String path = basePath + PDF_FILE_BASE_PATH + emr.getPatientId() + "/" + emr.getEmrId() + ".pdf";
        File file = new File(path);
        if (!file.exists()) {
            FileUtils.forceMkdirParent(file);
            FileOutputStream fos = new FileOutputStream(file);
            this.generatePDF(fos, emr);
            fos.close();
            LOGGER.info("病例PDF生成完成{} cost:{} ms, emrId:{}, path:{}", file.exists(), System.currentTimeMillis() - start, emr.getEmrId(), path);
        }
        return path;
    }

    private void generatePDF(OutputStream ouput, EmrPdfUtil.EmrBO emr) throws DocumentException, IOException {

        // 页面大小
        Rectangle rect = new Rectangle(PageSize.A4);
        Document document = new Document(rect);
        // 创建PdfWriter对象
        PdfWriter writer = PdfWriter.getInstance(document, ouput);
        // 打开文档
        document.open();
        // 页边空白
        document.setMargins(20, 20, 30, 40);

        // 设置医院图章
        File file = new File(HOSPITAL_SEAL_PATH);
        if (file.exists()) {
            Image image = Image.getInstance(HOSPITAL_SEAL_PATH);
            image.setAbsolutePosition(300, 680);
            image.scaleToFit(150, 150);
            document.add(image);
        } else {
            LOGGER.warn("互联网医院图章不存在，请检查图章文件目录 {}", HOSPITAL_SEAL_PATH);
        }

        // title
        Paragraph titleRow = new Paragraph(emr.getHospitalName() + "患者病例", firsetTitleFont);
        titleRow.setAlignment(PdfContentByte.ALIGN_CENTER);
        titleRow.setSpacingAfter(20);
        document.add(titleRow);

        // 分割线
        Paragraph lineParagraph = new Paragraph();
        lineParagraph.add(line);
        lineParagraph.setSpacingAfter(20);
        document.add(lineParagraph);

        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm");
        String createdTime = dateFormat.format(emr.getCreatedAt());

        // 第一行
        Phrase name = this.buildPhrase("姓名：", emr.getName(), fontContentBOLD, fontContent);
        Phrase time = this.buildPhrase("时间：", createdTime, fontContentBOLD, fontContentEn);
        document.add(this.buildTable(new float[]{0.7f, 0.3f}, 95, 0, 0, name, time));

        // 第二行
        String genderStr = emr.getGender() == 0 ? "女" : "男";
        Phrase gender = this.buildPhrase("性别：", genderStr, fontContentBOLD, fontContent);
        Phrase age = this.buildPhrase("年龄：", emr.getAge() , fontContentBOLD, fontContent);
        document.add(this.buildTable(new float[]{0.7f, 0.3f}, 95, 0, 0, gender, age));

        // 第三行
        Phrase department = this.buildPhrase("科室：", emr.getDepartmentName(), fontContentBOLD, fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 2, department));

        document.add(line);

        // 第四行(主诉标题)
        Paragraph chiefComplaintPhrase = new Paragraph("主诉/现病史", fontContent2);
        document.add(this.buildTable(new float[]{1f}, 95, 5, 2, chiefComplaintPhrase));

        // 第五行(主诉内容)
        Paragraph chiefComplaintContentPhrase = new Paragraph(StringUtils.isEmpty(emr.getChiefComplaint()) ? "无" : emr.getChiefComplaint(),
                fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 5, chiefComplaintContentPhrase));

        // 第六行(既往史标题)
        Paragraph pastMedicalHistoryPhrase = new Paragraph("既往史", fontContent2);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 2, pastMedicalHistoryPhrase));

        // 第七行(既往史内容)
        Paragraph pastMedicalHistoryContentPhrase = new Paragraph(StringUtils.isEmpty(emr.getPastMedicalHistory()) ? "无" :
                                                                          emr.getPastMedicalHistory(), fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 5, pastMedicalHistoryContentPhrase));

        // 检查指标
        Paragraph checkParagraphTitle = new Paragraph("检查指标", fontContent2);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 2, checkParagraphTitle));

        Phrase temperature = this.buildPhrase("体温：", emr.getTemperature() == null ? "无" : emr.getTemperature() + " ℃", fontContent,
                fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 0, temperature));

        Phrase weight = this.buildPhrase("体重：", emr.getWeight() == null ? "无" : emr.getWeight() + " kg", fontContent, fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 0, weight));

        Phrase heartRate = this.buildPhrase("心率：", emr.getHeartRate() == null ? "无" : emr.getHeartRate() + " bpm", fontContent,
                fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 0, heartRate));

        Phrase systolicPressure = this.buildPhrase("收缩压：", emr.getSystolicPressure() == null ? "无" : emr.getSystolicPressure() + " mmbhg",
                fontContent,
                fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 0, systolicPressure));

        Phrase diastolicPressure = this.buildPhrase("舒张压：", emr.getDiastolicPressure() == null ? "无" : emr.getDiastolicPressure() + " mmbhg",
                fontContent, fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 5, diastolicPressure));


        // 诊断
        Paragraph diagnosisTitle = new Paragraph("诊断", fontContent2);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 2, diagnosisTitle));

        String diagnosis = String.join(",", emr.getDiagnosis());
        Paragraph diagnosisContent = new Paragraph(diagnosis, fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 2, diagnosisContent));

        document.add(line);

        if (emr.getReportImgUrls() != null && emr.getReportImgUrls().size() > 0) {
            for (String url : emr.getReportImgUrls()) {
                File imagefile = new File(url);
                if (imagefile.exists()) {
                    Image image = Image.getInstance(imagefile.getPath());
                    image.scaleToFit(80, 80);
                    document.add(image);
                }
            }
            document.add(line);
        }

        Phrase doctor = this.buildPhrase("医生：", emr.getDoctorName(), fontContentBOLD, fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 2, 0, doctor));

        Phrase hospital = this.buildPhrase("医院：", emr.getHospitalName(), fontContentBOLD, fontContent);
        document.add(this.buildTable(new float[]{1f}, 95, 0, 0, hospital));

        document.close();

    }

    private Phrase buildPhrase(String title, String content, Font titleFont, Font contentFont) {
        Phrase phrase = new Phrase();
        Chunk chunkTitle = new Chunk(title, titleFont);
        Chunk chunkContent = new Chunk(content, contentFont);
        phrase.add(chunkTitle);
        phrase.add(chunkContent);
        return phrase;
    }

    private PdfPCell buildCell(Phrase phrase) {
        PdfPCell pdfPCell = new PdfPCell(phrase);
        pdfPCell.disableBorderSide(Rectangle.TOP); // 隐藏单元格周边的上边框
        pdfPCell.disableBorderSide(Rectangle.BOTTOM);// 隐藏单元格周边的下边框
        pdfPCell.disableBorderSide(Rectangle.LEFT); // 隐藏单元格周边的左边框
        pdfPCell.disableBorderSide(Rectangle.RIGHT);// 隐藏单元格周边的右框
        return pdfPCell;
    }

    private PdfPTable buildTable(float relativeWidths[], int widthPercentage, int pacingBefore, int pacingAfter, Phrase... phrases) {
        PdfPTable pdfPTable = new PdfPTable(relativeWidths);
        pdfPTable.setWidthPercentage(widthPercentage);
        for (Phrase phrase : phrases) {
            pdfPTable.addCell(this.buildCell(phrase));
        }
        pdfPTable.setSpacingBefore(pacingBefore);
        pdfPTable.setSpacingAfter(pacingAfter);
        return pdfPTable;
    }

    @Builder
    @Data
    public static class EmrBO {

        private String emrId;
        private Long patientId;
        private String name;
        private Integer gender;
        private String departmentName;
        private String age;
        private String ageUnit;
        private Date createdAt;

        /**
         * 主诉
         */
        private String chiefComplaint;
        /**
         * 既往史
         */
        private String pastMedicalHistory;
        /**
         * 体温
         */
        private Double temperature;
        /**
         * 体重
         */
        private Double weight;
        /**
         * 心率
         */
        private Integer heartRate;
        /**
         * 收缩压
         */
        private Integer systolicPressure;
        /**
         * 舒张压
         */
        private Integer diastolicPressure;
        /**
         * 诊断
         */
        private List<String> diagnosis;
        /**
         * 报告图片
         */
        private List<String> reportImgUrls;
        /**
         * 医生
         */
        private String doctorName;
        /**
         * 医院
         */
        private String hospitalName;

    }
}
